﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using blacksoft.Models;
using blacksoft.Constantes;

namespace blacksoft.Controllers
{
    public class RutaController : Controller
    {
        private inf245travelbusEntities db = new inf245travelbusEntities();

        private ActionResult ValidarPermiso()
        {
            //NO ESTOY LOGUEADO EN EL SISTEMA
            if (Session["Permisos"] == null)
            {
                TempData["LogueatePrimero"] = SystemField.NO_LOGUEADO;
                return RedirectToAction("Index", "ValidarLogin");
            }
            //ESTOY LOGUEADO PERO NO TENGO PERMISO PARA REALIZAR ESTA ACCION
            if (!PerfilsController.TienePermiso((int)Session["Permisos"], PerfilsController.ADMINISTRACION))
            {
                TempData["SinPermiso"] = SystemField.SIN_PERMISO;
                return RedirectToAction("Index", "MainPageEmployes");
            }
            return null;
        }

        private class EstadoRuta
        {
            public string valor { get; set; }
            public string estado { get; set; }

            public EstadoRuta(string valor, string estado)
            {
                this.valor = valor;
                this.estado = estado;
            }
        }
        private List<EstadoRuta> estados_ruta = new List<EstadoRuta> { new EstadoRuta("AC", "Activo"), new EstadoRuta("IN", "Inactivo"), new EstadoRuta("AN", "Anulado") };

        private void MostrarEscalas(Ruta ruta)
        {
            var terminales = db.Terminal.Where(t =>t.Estado!="AN");
            var escalas = ruta.Escala;
            var escalas_x_ruta = new HashSet<int>(ruta.Escala.Select(e => e.IDTerminal));
            var escala_lst = new List<EscalaAsignada>();
            foreach (var item in terminales)
            {
                escala_lst.Add(new EscalaAsignada
                {
                    IDTerminal = item.IDTerminal,
                    Nombre = item.Nombre,
                    Asignado = escalas_x_ruta.Contains(item.IDTerminal),
                    Duracion = escalas_x_ruta.Contains(item.IDTerminal) ? escalas.Single(e => e.IDTerminal == item.IDTerminal).Duracion : "",
                    NumeroSecuencia = escalas_x_ruta.Contains(item.IDTerminal) ? escalas.Single(e => e.IDTerminal == item.IDTerminal).NumeroSecuencia : 0
                });
            }
            if (ruta.TerminalOrigen != null) //no se muestran las terminales de origen y destino como posibles escalas
            {
                EscalaAsignada origen = escala_lst.Single(e => e.Nombre == ruta.TerminalOrigen);
                EscalaAsignada destino = escala_lst.Single(e => e.Nombre == ruta.TerminalDestino);
                escala_lst.Remove(origen);
                escala_lst.Remove(destino);
            }
            ViewBag.Escalas = escala_lst;
        }

        private void ModificarEscalas(int[] escalas, Ruta ruta, string[] duracion, int[] secuencia)
        {
            if (escalas == null)
            {
                foreach (var item in db.Escala.Where(e=>e.IDRuta==ruta.IDRuta))
                {
                    db.Escala.Remove(item);
                }
                return;
            }
            var terminales = db.Terminal.Where(t => t.Estado != "AN");
            var escalasHS = new HashSet<int>(escalas);
            var escalas_x_ruta = new HashSet<int>(db.Escala.Where(e=>e.IDRuta==ruta.IDRuta).Select(e => e.IDTerminal));
            int indice=0;
            /*se agrega o modifica cada escala elegida*/
            foreach (var item in escalasHS)
            {
                if (!escalas_x_ruta.Contains(item)) //se agrega escala q no existia
                {
                    Escala escala = new Escala();
                    escala.IDRuta = ruta.IDRuta;
                    escala.IDTerminal = item;
                    escala.Duracion = duracion[indice];
                    escala.NumeroSecuencia = secuencia[indice++];
                    db.Escala.Add(escala);
                }
                else
                {
                    Escala escala = db.Escala.Single(e => e.IDRuta == ruta.IDRuta && e.IDTerminal == item);
                    escala.Duracion = duracion[indice];
                    escala.NumeroSecuencia = secuencia[indice++];
                    db.Entry(escala).State = EntityState.Modified;
                }
            }
            foreach (var item in terminales)
            {
                if (escalas_x_ruta.Contains(item.IDTerminal) && !escalasHS.Contains(item.IDTerminal) && item.Nombre!=ruta.TerminalDestino)
                {
                    Escala escala = db.Escala.Single(e => e.IDRuta == ruta.IDRuta && e.IDTerminal == item.IDTerminal);
                    db.Escala.Remove(escala);
                }
            }
        }

        // GET: /Ruta/
        public ActionResult Index(string origen, string destino, string escala, string estado)
        {
            ActionResult permiso = ValidarPermiso();
            if (permiso != null) return permiso;
            //Query de la lista de terminales registradas para filtrar
            ViewBag.escala = ViewBag.destino = ViewBag.origen = new SelectList(db.Terminal.Where(t => t.Estado != "AN").OrderBy(t => t.Nombre), "Nombre", "Nombre");
            //Lista de estados existentes para el filtro
            ViewBag.estado = new SelectList(estados_ruta, "valor", "estado");
            
            //Select de todas las rutas, excepto las que tienen estado Anulado
            var rutas = db.Ruta.Include(r => r.Escala).Where(r => r.Estado != "AN");
            
            /*********************************************************Filtro del listado**********************************************************/
            if (!String.IsNullOrEmpty(estado))
            {
                rutas = db.Ruta.Include(r => r.Escala).Where(r => r.Estado == estado);
            }
            //Si NO tiene permiso Global
            if (!PerfilsController.TienePermiso((int)Session["Permisos"], PerfilsController.GLOBAL))
            {
                int id_terminal = (int)Session["IDTerminal"];
                string terminal_destino = db.Terminal.Single(t => t.IDTerminal == id_terminal).Nombre;
                //Solo se muestran los registros de la terminal
                rutas = rutas.Where(r => r.IDTerminal == id_terminal || r.TerminalDestino == terminal_destino);
            }

            if (!String.IsNullOrEmpty(origen))
            {
                rutas = rutas.Where(r => r.TerminalOrigen == origen);
            }
            if (!String.IsNullOrEmpty(destino))
            {
                rutas = rutas.Where(r => r.TerminalDestino == destino);
            }
            if (!String.IsNullOrEmpty(escala))
            {
                rutas = rutas.Where(r=>r.Escala.Any(e=>e.Terminal.Nombre==escala));
            }
            /*********************************************************Filtro del listado**********************************************************/
            return View(rutas.ToList());
        }

        // GET: /Ruta/Details/5
        public ActionResult Details(int? id)
        {
            ActionResult permiso = ValidarPermiso();
            if (permiso != null) return permiso;
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Ruta ruta = db.Ruta.Find(id);
            if (ruta == null)
            {
                return HttpNotFound();
            }
            return View(ruta);
        }

        // GET: /Ruta/Create
        public ActionResult Create()
        {
            ActionResult permiso = ValidarPermiso();
            if (permiso != null) return permiso;
            //Si NO tiene permiso Global
            if (!PerfilsController.TienePermiso((int)Session["Permisos"], PerfilsController.GLOBAL))
            {
                int id_terminal = (int)Session["IDTerminal"];
                ViewBag.TerminalOrigen = new SelectList(db.Terminal.Where(t => t.Estado != "AN" && t.IDTerminal==id_terminal), "Nombre", "Nombre");
            }
            else ViewBag.TerminalOrigen = new SelectList(db.Terminal.Where(t => t.Estado != "AN"), "Nombre", "Nombre");
            ViewBag.TerminalDestino = new SelectList(db.Terminal.Where(t => t.Estado != "AN"), "Nombre", "Nombre");
            var ruta = new Ruta();
            try
            {
                MostrarEscalas(ruta);
            }
            catch
            {
                TempData["error"] = "Ocurrió un error inesperado. Intentelo otra vez.";
                return RedirectToAction("Index");
            }
            return View();
        }

        // POST: /Ruta/Create
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "TerminalOrigen,TerminalDestino,TiempoViaje,Distancia,Estado,PuntosAGanar")] Ruta ruta, int[] escalas, string[] duracion, int[] secuencia)
        {
            ActionResult permiso = ValidarPermiso();
            if (permiso != null) return permiso;
            /*var rutas = db.Ruta.Where(r => (r.TerminalOrigen == ruta.TerminalOrigen) && (r.TerminalDestino == ruta.TerminalDestino) && (r.Estado!="AN"));
            if (rutas.Count()>0 )
            { //Ruta ya registrada: se verifican las terminales origen y destino elegidas
                TempData["create"] = "Ya existe una ruta entre las terminales seleccionadas.";
                ViewBag.TerminalOrigen = new SelectList(db.Terminal.Where(t => t.Estado != "AN"), "Nombre", "Nombre");
                ViewBag.TerminalDestino = new SelectList(db.Terminal.Where(t => t.Estado != "AN"), "Nombre", "Nombre");
                MostrarEscalas(ruta);
                return View(ruta);
            }*/
            
            try
            {
                if (!string.IsNullOrEmpty(ruta.TerminalOrigen))
                {
                    var origen = db.Terminal.Single(t => t.Nombre == ruta.TerminalOrigen && t.Estado != "AN");
                    ruta.Origen = origen.Departamento;
                    ruta.IDTerminal = origen.IDTerminal;
                }
                if (!string.IsNullOrEmpty(ruta.TerminalDestino))
                {
                    ruta.Destino = db.Terminal.Single(t => t.Nombre == ruta.TerminalDestino && t.Estado != "AN").Departamento;
                }
                
                if (ModelState.IsValid)
                {
                    db.Ruta.Add(ruta);
                    db.SaveChanges();
                    if (escalas != null)
                    {
                        var aux_secuencia = new List<int>();
                        var aux_duracion = new List<string>();
                        for (int i = 0; i < secuencia.Count(); i++)
                        {
                            if (secuencia[i] != 0)
                            {
                                aux_secuencia.Add(secuencia[i]);
                                aux_duracion.Add(duracion[i]);
                            }
                        }
                        ruta.Escala = new List<Escala>();
                        int j = 0;
                        foreach (var item in escalas)
                        {
                            Escala escala = new Escala();
                            escala.IDRuta = ruta.IDRuta;
                            escala.IDTerminal = db.Terminal.Find(item).IDTerminal;
                            escala.Duracion = aux_duracion[j];
                            escala.NumeroSecuencia = aux_secuencia[j++];
                            db.Escala.Add(escala);
                        }
                    }
                    /*se agrega la terminal destino a la tabla Escalas*/
                    if (!string.IsNullOrEmpty(ruta.TerminalDestino))
                    {
                        Escala escala = new Escala();
                        escala.IDRuta = ruta.IDRuta;
                        escala.IDTerminal = db.Terminal.Single(t => t.Nombre == ruta.TerminalDestino && t.Estado != "AN").IDTerminal;
                        escala.Duracion = ruta.TiempoViaje.ToString();
                        escala.NumeroSecuencia = -1; //indica que es la terminal destino
                        db.Escala.Add(escala);
                    }
                    db.SaveChanges();
                    TempData["create_success"] = "Ruta registrada correctamente.";
                    return RedirectToAction("Index");
                }
            }
            catch
            {
                TempData["create"] = "Ocurrió un error inesperado, NO se pudo registrar la ruta. Intentelo otra vez.";
            }
            ViewBag.TerminalOrigen = new SelectList(db.Terminal.Where(t => t.Estado != "AN"), "Nombre", "Nombre", ruta.TerminalOrigen);
            ViewBag.TerminalDestino = new SelectList(db.Terminal.Where(t => t.Estado != "AN"), "Nombre", "Nombre", ruta.TerminalDestino);
            try
            {
                MostrarEscalas(ruta);
            }
            catch
            {
                TempData["error"] = "Ocurrió un error inesperado, NO se pudo registrar la ruta. Intentelo otra vez.";
                return RedirectToAction("Index");
            }
            return View(ruta);
        }

        // GET: /Ruta/Edit/5
        public ActionResult Edit(int? id)
        {
            ActionResult permiso = ValidarPermiso();
            if (permiso != null) return permiso;
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Ruta ruta = db.Ruta.Include(r => r.Escala).Where(r=> r.IDRuta == id).Single();
            try
            {
                MostrarEscalas(ruta);
            }
            catch
            {
                TempData["error"] = "Ocurrió un error inesperado. Intentelo otra vez.";
                return RedirectToAction("Index");
            }
            if (ruta == null)
            {
                return HttpNotFound();
            }
            
            return View(ruta);
        }

        // POST: /Ruta/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "IDRuta,Origen,Destino,TerminalOrigen,TerminalDestino,TiempoViaje,Distancia,Estado,PuntosAGanar,IDTerminal")] Ruta ruta, int[] escalas, string[] duracion, int[] secuencia)
        {
            ActionResult permiso = ValidarPermiso();
            if (permiso != null) return permiso;
            try
            {
                if (ModelState.IsValid)
                {
                    if (escalas != null)
                    {
                        var aux_secuencia = new List<int>();
                        var aux_duracion = new List<string>();
                        for (int i = 0; i < secuencia.Count(); i++)
                        {
                            if (secuencia[i] != 0)
                            {
                                aux_secuencia.Add(secuencia[i]);
                                aux_duracion.Add(duracion[i]);
                            }
                        }
                        duracion = aux_duracion.ToArray();
                        secuencia = aux_secuencia.ToArray();
                    }
                    ModificarEscalas(escalas, ruta,duracion,secuencia);
                    db.Entry(ruta).State = EntityState.Modified;
                    db.SaveChanges();
                    TempData["edit_success"] = "Ruta modificada correctamente.";
                    return RedirectToAction("Index");
                }
            }
            catch
            {
                TempData["edit"] = "Ocurrió un error inesperado, NO se pudieron guardar los cambios a la ruta. Intentelo otra vez.";
            }
            try
            {
                MostrarEscalas(ruta);
            }
            catch
            {
                TempData["error"] = "Ocurrió un error inesperado, NO se pudieron guardar los cambios a la ruta. Intentelo otra vez.";
                return RedirectToAction("Index");
            }
            return View(ruta);
        }

        // GET: /Ruta/Delete/5
        public ActionResult Delete(int? id, bool? saveChangesError=false)
        {
            ActionResult permiso = ValidarPermiso();
            if (permiso != null) return permiso;
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            if (saveChangesError.GetValueOrDefault())
            {
                TempData["delete"] = "NO se pudo eliminar el registro.";
            }
            Ruta ruta = db.Ruta.Find(id);
            if (ruta == null)
            {
                return HttpNotFound();
            }
            return View(ruta);
        }

        // POST: /Ruta/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            ActionResult permiso = ValidarPermiso();
            if (permiso != null) return permiso;
            try
            {
                Ruta ruta = db.Ruta.Find(id);
                ruta.Estado = "AN"; //solo se cambia el estado a Anulado
                //db.Ruta.Remove(ruta);
                db.SaveChanges();
            }
            catch
            {
                return RedirectToAction("Delete", new { id = id, saveChangesError = true });
            }
            TempData["delete_success"] = "Ruta eliminada correctamente.";
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

    }
}
